package e2e

import (
	"fmt"
	"strconv"
	"testing"

	"github.com/lab-online/pkg/auth"
	"github.com/lab-online/pkg/e2e"
	"github.com/lab-online/pkg/resp"
	"github.com/stretchr/testify/assert"
)

type teacherInfo struct {
	Name     string
	Username string
	Role     uint
}

type searchClassReqQuery struct {
	ID      uint
	Name    string
	Teacher string
	Student string
}

type searchClassRespDataItem struct {
	ID          uint
	Name        string
	Teacher     *teacherInfo
	CourseID    uint
	Description string
}

type searchClassResp = resp.SuccessRespBody[[]searchClassRespDataItem]

func (ctx *context) defineSearchClassRequest(
	username string, role auth.Role,
	query *searchClassReqQuery,
) *e2e.Request {
	return &e2e.Request{
		Method: "GET",
		Path:   ctx.Prefix + "/v1/classes",
		Query: map[string]string{
			"id":      strconv.Itoa(int(query.ID)),
			"name":    query.Name,
			"teacher": query.Teacher,
			"student": query.Student,
		},
		Header: map[string]string{
			"Authorization": ctx.GenBearerToken(username, role),
		},
	}
}

func (ctx *context) CaseSearchClass1() (string, func(*testing.T)) {
	ctx.utilsCreateUser("00240304", auth.RoleTeacher)
	ctx.utilsCreateCourse(10000, "高等数学")
	ctx.utilsCreateClass(10000, "高等数学A班for search", "00240304", 10000)
	ctx.utilsCreateClass(10001, "高等数学B班for search", "00240304", 10000)

	request := ctx.defineSearchClassRequest("admin1", auth.RoleAdmin, &searchClassReqQuery{
		Name: "高等数学",
	})
	return "按班级名称搜索班级", func(t *testing.T) {
		response := ctx.JSONRequest(request)

		assert.Equal(t, 200, response.Code)

		body := e2e.JSONBodyParser[searchClassResp](response)

		assert.Equal(t, 20201, body.Code)

		assert.Equal(t, 2, len(body.Data))
		assert.ElementsMatch(t, []string{"高等数学A班for search", "高等数学B班for search"},
			[]string{body.Data[0].Name, body.Data[1].Name})
		assert.ElementsMatch(t, []string{"00240304", "00240304"},
			[]string{body.Data[0].Teacher.Username, body.Data[1].Teacher.Username})
		assert.ElementsMatch(t, []uint{10000, 10000},
			[]uint{body.Data[0].CourseID, body.Data[1].CourseID})
	}
}

func (ctx *context) CaseSearchClass2() (string, func(*testing.T)) {
	ctx.utilsCreateUser("00240304", auth.RoleTeacher)
	ctx.utilsCreateCourse(10000, "高等数学")
	ctx.utilsCreateCourse(10001, "线性代数")
	ctx.utilsCreateClass(10000, "高等数学A班for search", "00240304", 10000)
	ctx.utilsCreateClass(10001, "线性代数A班for search", "00240304", 10001)

	request := ctx.defineSearchClassRequest("admin1", auth.RoleAdmin, &searchClassReqQuery{
		Teacher: "00240304",
	})
	return "按教师工号搜索班级", func(t *testing.T) {
		response := ctx.JSONRequest(request)

		assert.Equal(t, 200, response.Code)

		body := e2e.JSONBodyParser[searchClassResp](response)

		assert.Equal(t, 20201, body.Code)

		assert.Equal(t, 2, len(body.Data))
		assert.ElementsMatch(t, []string{"高等数学A班for search", "线性代数A班for search"},
			[]string{body.Data[0].Name, body.Data[1].Name})
		assert.ElementsMatch(t, []string{"00240304", "00240304"},
			[]string{body.Data[0].Teacher.Username, body.Data[1].Teacher.Username})
		assert.ElementsMatch(t, []uint{10000, 10001},
			[]uint{body.Data[0].CourseID, body.Data[1].CourseID})
	}
}

func (ctx *context) CaseSearchClass3() (string, func(*testing.T)) {
	// 教师
	ctx.utilsCreateUser("00240408", auth.RoleTeacher)
	ctx.utilsCreateUser("01240408", auth.RoleStudent)
	// 学生
	ctx.utilsCreateUser("02240408", auth.RoleStudent)

	ctx.utilsCreateCourse(24040800, "高等数学")
	ctx.utilsCreateCourse(24040801, "线性代数")

	ctx.utilsCreateClass(24040802, "高等数学A班for search", "00240408", 24040800)
	ctx.utilsCreateClass(24040803, "线性代数A班for search", "01240408", 24040801)

	ctx.utilsCreateStudent(24040802, "02240408")
	ctx.utilsCreateStudent(24040803, "02240408")

	request := ctx.defineSearchClassRequest("admin1", auth.RoleStudent, &searchClassReqQuery{
		Student: "02240408",
	})
	return "通过学生学号搜索自己所在的班级", func(t *testing.T) {
		response := ctx.JSONRequest(request)

		assert.Equal(t, 200, response.Code)

		body := e2e.JSONBodyParser[searchClassResp](response)
		fmt.Println(body)

		assert.Equal(t, 20201, body.Code)

		assert.Equal(t, 2, len(body.Data))
		assert.ElementsMatch(t, []string{"高等数学A班for search", "线性代数A班for search"},
			[]string{body.Data[0].Name, body.Data[1].Name})
		assert.ElementsMatch(t, []string{"00240408", "01240408"},
			[]string{body.Data[0].Teacher.Username, body.Data[1].Teacher.Username})
		assert.ElementsMatch(t, []uint{24040800, 24040801},
			[]uint{body.Data[0].CourseID, body.Data[1].CourseID})
	}
}
